﻿using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;

namespace MefBasic.Extensions
{
    public static class ApplicationExtension
    {
        public static event EventHandler WindowEnabled;

        public static void DisableWindow(this Application source)
        {
            source.DisableWindow(0.5);
        }

        public static void DisableWindow(this Application source, double opacity)
        {
            if (!ContainsValidWindow(source)) return;

            var window = source.MainWindow ?? source.Windows[0];
            DisableWindow(window, opacity);
        }

        private static void DisableWindow(ContentControl window, double opacity)
        {
            window.Focusable = true;
            window.MouseEnter += WindowMouseEnter;
            if (((FrameworkElement)window.Content).IsEnabled == false)
                return;
            ((FrameworkElement)window.Content).IsEnabled = false;
            MakeDisabledOpacity(window, opacity);
        }

        private static void MakeDisabledOpacity(UIElement window, double opacity)
        {
            window.Opacity = opacity;
        }

        private static bool ContainsValidWindow(Application source)
        {
            return source != null && source.Windows.Count > 0;
        }

        static void WindowMouseEnter(object sender, MouseEventArgs e)
        {
            Keyboard.Focus(sender as UIElement);
        }

        public static void EnableWindow(this Application source)
        {
            if (source != null && source.Windows.Count > 0)
            {
                var window = source.MainWindow ?? source.Windows[0];
                if (window != null)
                {
                    window.MouseEnter -= WindowMouseEnter;
                    if (((FrameworkElement)window.Content).IsEnabled)
                        return;
                    ((FrameworkElement)window.Content).IsEnabled = true;
                    window.Opacity = 1;
                }
                if (WindowEnabled != null)
                    WindowEnabled(source, new EventArgs());
            }
        }
        public static bool IsWindowEnabled(this Application source)
        {
            if (source == null)
                return false;
            var isEnabled = true;
            if (source.Windows.Count > 0)
            {
                var window = source.MainWindow ?? source.Windows[0];
                if (window != null) isEnabled = ((FrameworkElement)window.Content).IsEnabled;
            }
            return isEnabled;
        }

        public static void DoEvents(this Application source)
        {
            if (source == null)
                return;
            source.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
        }
        public static void Wait(this Application source, double miliseconds)
        {
            var start = DateTime.Now;
            while ((DateTime.Now - start).TotalMilliseconds < miliseconds)
            {
                source.DoEvents();
            }
        }

        private static int _priorityCount;
        public static void ResetDoEventsPriority(this Application source)
        {
            _priorityCount = 0;
        }

        public static void DoEvents(this Application source, int priority)
        {
            if (++_priorityCount != priority) return;
            _priorityCount = 0;
            DoEvents(source);
        }

        public static void BeginInvoke(this Application source, Action action)
        {
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new ThreadStart(action));
        }

        public static void ActivateMainWindow(this Application source)
        {
            if (source.MainWindow!=null)
                source.MainWindow.Activate();
        }
    }
}
